package com.course.gateway.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @author: Durian
 * @date: 2021/5/2 11:56
 */
@Slf4j
@Configuration
@RequiredArgsConstructor
public class GlobalExceptionConfiguration implements ErrorWebExceptionHandler {

    private final ObjectMapper objectMapper;

    @Override
    public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
        ServerHttpResponse response = serverWebExchange.getResponse();

        if (response.isCommitted()) {
            return Mono.error(throwable);
        }

        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        if (throwable instanceof ResponseStatusException) {
            response.setStatusCode(((ResponseStatusException) throwable).getStatus());
        }

        return response
                .writeWith(Mono.fromSupplier(() -> {
                    DataBufferFactory bufferFactory = response.bufferFactory();
                    try {
                        int code = 503;
                        if (throwable instanceof ResponseStatusException) {
                            code = ((ResponseStatusException) throwable).getStatus().value();
                        }
                        log.error("Gateway error", throwable);
                        return bufferFactory.wrap(objectMapper.writeValueAsBytes(Result.failure(code, "网关错误")));
                    } catch (JsonProcessingException e) {
                        log.warn("Error writing response", throwable);
                        return bufferFactory.wrap(new byte[0]);
                    }
                }));
    }

    @Setter
    @Getter
    private static class Result{
        private boolean success;
        private int code;
        private String msg;

        static Result failure(int code, String message) {
            Result result = new Result();
            result.setCode(code);
            result.setMsg(message);
            result.setSuccess(false);
            return result;
        }
    }
}
